import traci

import traci.constants as tc

# 开启
ON = 1
# 关闭
OFF = 0
# 删除
DEL = -1
# 恶劣天气区域监控距离
DEFAULT_DISTANCE = 20

# 恶劣天气区域更新中（保证操作处于一个step中）
building = False

class BadWeatherDomain:

    def __init__(self):
        self.weather_polygon = {}

    def set_bad_weather_polygon(self, edge: str, lane_index: int, pos: list, switch=ON):
        """
        新增恶劣天气区 (str, int, double, list((double, double)), integer) -> None
        :param edge: 边缘
        :param lane_index: 道路序号
        :param pos: 区域坐标集合
        :param switch: 开关
        :return:
        """
        polygon_id = edge + '_' + str(lane_index)
        accident_item = _BadWeatherItem(polygon_id, edge, lane_index, pos, switch)
        self.weather_polygon[polygon_id] = accident_item
        traci.lane.setAllowed(polygon_id, ['custom2'])
        traci.edge.subscribeContext(edge, tc.CMD_GET_VEHICLE_VARIABLE, 20, [tc.VAR_LANE_INDEX, tc.VAR_TYPE])

    def get_bad_weather_polygon(self, polygon_id: str):
        """
        获取指定恶劣天气区域 (str) -> AccidentItem
        :param polygon_id: 恶劣天气区域id
        :return: AccidentItem
        """
        return self.weather_polygon.get(polygon_id)

    def get_bad_weather_polygon_list(self):
        """
        获取所有恶劣天气区域
        :return: list(dict)
        """
        if len(self.weather_polygon) < 1:
            return []
        return list(map(lambda item: item[1].to_dict(), self.weather_polygon.items()))

    def control_bad_weather(self, polygon_id: str, switch: int):
        """
        控制恶劣天气区域 （str, int） -> int
        :param polygon_id: 区域id
        :param switch: -1：删除 0：关闭 1：开启
        :return: 0: 失败 1：成功
        """
        assert polygon_id in self.weather_polygon.keys(), '恶劣天气区域不存在'
        result = 0
        accident_item = self.weather_polygon[polygon_id]
        if accident_item is not None and accident_item.switch != switch:
            if switch == OFF:
                self.weather_polygon[polygon_id].switch = 0
                traci.lane.setDisallowed(polygon_id, [])
                traci.edge.unsubscribeContext(accident_item.edge, tc.CMD_GET_VEHICLE_VARIABLE, DEFAULT_DISTANCE)
                result = 1
            elif switch == ON:
                self.weather_polygon[polygon_id].switch = 1
                traci.lane.setAllowed(polygon_id, ['custom2'])
                traci.edge.subscribeContext(accident_item.edge, tc.CMD_GET_VEHICLE_VARIABLE, DEFAULT_DISTANCE,
                                            [tc.VAR_LANE_INDEX, tc.VAR_TYPE])
                result = 1
            elif switch == DEL:
                del self.weather_polygon[polygon_id]
                traci.lane.setDisallowed(polygon_id, [])
                traci.edge.unsubscribeContext(accident_item.edge, tc.CMD_GET_VEHICLE_VARIABLE, DEFAULT_DISTANCE)
                result = 1
        return result


class _BadWeatherItem:

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls)

    def __init__(self, polygon_id, points, speed_limit, radius, switch=1):
        self._polygon_id = polygon_id
        self._points = points
        self._speedLimit = speed_limit
        self._radius = radius
        self._switch = switch

    def to_dict(self):
        return {
            'polygonId': self._polygon_id,
            'points': self._points,
            'speedLimit': self._speedLimit,
            'radius': self._radius,
            'switch': self._switch
        }
